/**
 * ImageUtils.java
 *
 *
 * $LastChangedBy: allen $
 * $LastChangedDate: 2007-12-07 15:48:57 +0800 $
 * $Revision: 1400 $
 */
package com.myspace.common.util.image;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.renderable.ParameterBlock;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

import javax.media.jai.Interpolation;
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

public class ImageUtils {

	public static final int IMAGE_SCOPE = 115;

	// public static final int IMAGE_SCOPE = 120;

	private static Logger log = Logger.getLogger(ImageUtils.class);

	public static void main(String[] args) throws Exception {

		File oldFile = new File("c:\\test2.jpg");
		long begin = System.currentTimeMillis();
		for(int i=0;i<1;i++){
			File newFile = new File("c:\\test2_"+i+".jpg");
			ImageUtils.bulidImage(oldFile, newFile);
		}
		long end = System.currentTimeMillis();
		System.out.println(end - begin);

//		byte[] data = ImageUtils.cutImage(oldFile, 64);
//		createFile(newFile, data);
	}


	public static byte[] cutImage(File originalFile,int scope)
			throws Exception {
		byte[] newBinary = convertImageFile(originalFile,scope,true);
		return newBinary;
	}

	public static void bulidImage(File originalFile, File newFile)
			throws Exception {
		byte[] newBinary = convertImageFile(originalFile,IMAGE_SCOPE,false);
		createFile(newFile, newBinary);
	}

	public static byte[] rescaleBMP(byte[] content , int scope, boolean isCut) {

		BufferedInputStream sBuf = null;
		ByteArrayOutputStream ret = null;
		try {
			sBuf = new BufferedInputStream(new ByteArrayInputStream(content));
			ret = new ByteArrayOutputStream();

			java.awt.Image src = BMPDecoder.read(sBuf);
			int width = src.getWidth(null);
			int height = src.getHeight(null);

			BufferedImage srcImage = new BufferedImage(width, height,
					BufferedImage.TYPE_INT_RGB);
			Graphics g = srcImage.getGraphics();
			g.drawImage(src, 0, 0, width, height, null);
			g.dispose();

			BufferedImage image = rescaleImage(srcImage,scope,isCut);
			if(isCut){
				image = cutImage(image,scope);
			}

			JPEGImageEncoder encodera = JPEGCodec.createJPEGEncoder(ret);
			encodera.encode(image);
			ret.flush();
			return ret.toByteArray();
		} catch (Exception e) {
			log.error(e);
		} finally {
			IOUtils.closeQuietly(ret);
			IOUtils.closeQuietly(sBuf);
		}
		return null;
	}

	public static byte[] rescaleGIF(byte[] content,  int scope, boolean isCut) {
		BufferedInputStream sBuf = null;
		ByteArrayOutputStream ret = null;
		try {
			sBuf = new BufferedInputStream(new ByteArrayInputStream(content));
			ret = new ByteArrayOutputStream();

			GifDecoder decoder = new GifDecoder();
			decoder.read(sBuf);
			BufferedImage src = decoder.getFrame(0);
			BufferedImage image = rescaleImage(src,scope,isCut);
			if(isCut){
				image = cutImage(image,scope);
			}

			JPEGImageEncoder encodera = JPEGCodec.createJPEGEncoder(ret);
			encodera.encode(image);
			ret.flush();
			return ret.toByteArray();
		} catch (Exception e) {
			log.error(e);
		} finally {
			IOUtils.closeQuietly(ret);
			IOUtils.closeQuietly(sBuf);
		}
		return null;
	}

	public static byte[] rescaleJPG(byte[] content, int scope, boolean isCut) {

		BufferedInputStream sBuf = null;
		ByteArrayOutputStream ret = null;
		try {
			sBuf = new BufferedInputStream(new ByteArrayInputStream(content));
			BufferedImage src = javax.imageio.ImageIO.read(sBuf);
			BufferedImage image =  rescaleImage(src,scope,isCut);

			if(isCut){
				image = cutImage(image,scope);
			}

			ret = new ByteArrayOutputStream();
			JPEGImageEncoder encodera = JPEGCodec.createJPEGEncoder(ret);
			encodera.encode(image);

			ret.flush();
			return ret.toByteArray();

		} catch (Exception e) {
			log.error(e);
		} finally {
			IOUtils.closeQuietly(ret);
			IOUtils.closeQuietly(sBuf);
		}
		return null;
	}

	public static BufferedImage cutImage(BufferedImage image,  int scope) {
		BufferedImage ret = null;

		if (image.getWidth() > scope) {
			ret = image.getSubimage(
					((int) ((image.getWidth() - scope)) / 2), 0, image.getHeight(),
					image.getHeight());
		} else if (image.getHeight() > scope) {
			ret = image.getSubimage(0,
					((int) ((image.getHeight() - scope)) / 2), image.getWidth(),
					image.getWidth());
		} else {
			ret = image;
		}
		return ret;
	}

	private static BufferedImage rescaleImage(BufferedImage image, int scope, boolean isCut) {
		int srcw = image.getWidth();
		int srch = image.getHeight();
		if (srcw < scope && srch < scope)
			return image;

		float ratio = 1.0f;
		if (srcw > scope || srch > scope) {
			float ratiow = (float) scope / (float) srcw;
			float ratioh = (float) scope / (float) srch;

			if(!isCut){
				ratio = (ratiow > ratioh) ? ratioh : ratiow;
			}else{
				ratio = (ratiow < ratioh) ? ratioh : ratiow;
			}
		}

		Image scaleImage = image.getScaledInstance((int) (Math.ceil(srcw * ratio)),
				(int) (Math.ceil(srch * ratio)), BufferedImage.SCALE_SMOOTH);

		BufferedImage result = new BufferedImage(scaleImage.getWidth(null), scaleImage
				.getHeight(null), BufferedImage.TYPE_INT_RGB);
		Graphics g = result.getGraphics();
		g.drawImage(scaleImage, 0, 0, null);
		g.dispose();

		return result;

//		ImageScale imageScale = new ImageScale();
//		return imageScale.imageZoomOut(image, (int)(Math.ceil(srcw * ratio)),
//				(int)(Math.ceil(srch * ratio)));
	}

	private static byte[] convertImageFile(File originalFile,int scope, boolean isCut){
		if(originalFile == null)
			throw new IllegalArgumentException("Picture file is null!");

		byte[] oldBinary = ImageUtils.getFileBinary(originalFile);
		byte[] newBinary = null;
		if(originalFile.getPath().toLowerCase().endsWith(".gif")){
			newBinary =  rescaleGIF(oldBinary,scope,isCut);
		}else if(originalFile.getPath().toLowerCase().endsWith(".bmp")){
			newBinary = rescaleBMP(oldBinary,scope,isCut);
		}else{
			newBinary = rescaleJPG(oldBinary,scope,isCut);
		}
		return newBinary;
	}


	private static byte[] getFileBinary(File file) {
		BufferedInputStream bis = null;
		try {
			bis = new BufferedInputStream(new FileInputStream(file));
			byte[] content = new byte[bis.available()];
			bis.read(content);
			return content;
		} catch (Exception e) {
			log.error("getFileBinary error: ", e);
		} finally {
			IOUtils.closeQuietly(bis);
		}
		return null;
	}

	private static void createFile(File file, byte[] content) throws Exception {
		BufferedOutputStream bufOut = null;
		try {
			bufOut = new BufferedOutputStream(new DataOutputStream(
					new FileOutputStream(file)));
			bufOut.write(content);
			bufOut.flush();
		} catch (Exception e) {
			throw e;
		} finally {
			IOUtils.closeQuietly(bufOut);
		}
	}

	@Deprecated
	public static byte[] cutImage(byte[] content, String format, int scope) {

		BufferedInputStream sBuf = null;
		ByteArrayOutputStream ret = null;
		try {
			byte[] newContent = rescaleImageMore(content, format, scope);
			if (newContent == null)
				return null;

			sBuf = new BufferedInputStream(new ByteArrayInputStream(newContent));

			BufferedImage newSrc = javax.imageio.ImageIO.read(sBuf);

			BufferedImage image = null;

			if (newSrc.getWidth() == newSrc.getHeight())
				return newContent;

			if (newSrc.getWidth() > scope) {
				image = newSrc.getSubimage(
						((int) ((newSrc.getWidth() - scope)) / 2), 0, scope,
						scope);
			} else if (newSrc.getHeight() > scope) {
				image = newSrc.getSubimage(0,
						((int) ((newSrc.getHeight() - scope)) / 2), scope,
						scope);
			} else {
				image = newSrc;
			}

			ret = new ByteArrayOutputStream();
			JPEGImageEncoder encodera = JPEGCodec.createJPEGEncoder(ret);
			encodera.encode(image);

			ret.flush();

			return ret.toByteArray();

		} catch (Exception e) {
			log.error(e);
		} finally {
			IOUtils.closeQuietly(ret);
			IOUtils.closeQuietly(sBuf);
		}
		return null;
	}

	@Deprecated
	public static byte[] rescaleImageMore(byte[] content, String format,
			int scope) {
		if (content == null)
			return null;

		if (StringUtils.isEmpty(format)) {
			format = "JPEG";
		}

		ByteArrayOutputStream ret = null;
		BufferedInputStream sBuf = null;
		try {
			// out of memory
			// stream = new ByteArraySeekableStream( content );

			// RenderedOp imagesrc = JAI.create( "stream", stream );
			// int srcw = imagesrc.getWidth( );
			// int srch = imagesrc.getHeight( );
			sBuf = new BufferedInputStream( new ByteArrayInputStream(content));

			// javax.imageio.ImageIO.setUseCache( true );
			// javax.imageio.ImageIO
			// .setCacheDirectory( new File( ImageManager.TEMP_PATH ) );

			BufferedImage imagesrc = javax.imageio.ImageIO.read(sBuf);
			imagesrc.flush();

			int srcw = imagesrc.getWidth();
			int srch = imagesrc.getHeight();

			Interpolation interp = Interpolation
					.getInstance(Interpolation.INTERP_BILINEAR);

			float ratiow = (float) scope / (float) srcw;
			float ratioh = (float) scope / (float) srch;
			float ratio = (ratiow < ratioh) ? ratioh : ratiow;

			ParameterBlock params = new ParameterBlock();
			params.addSource(imagesrc);
			params.add(ratio); // x scale factor
			params.add(ratio); // y scale factor
			params.add(0.0F); // x translate
			params.add(0.0F); // y translate
			params.add(interp); // interpolation method

			RenderedOp imagedest = JAI.create("scale", params);
			ret = new ByteArrayOutputStream();
			JAI.create("encode", imagedest, ret, format, null);
			return ret.toByteArray();
		} catch (Exception e) {
			log.error(e);
		} finally {
			IOUtils.closeQuietly(ret);
			IOUtils.closeQuietly(sBuf);
		}
		return null;
	}


}
